package org.kugua.strategy.impl;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.kugua.context.CaptchaContext;
import org.kugua.dto.Captcha;
import org.kugua.dto.SliderImage;
import org.kugua.enums.CaptchaEnum;
import org.kugua.image.ImageSelector;
import org.kugua.image.impl.SliderImageSelector;
import org.kugua.strategy.AbstractSliderCaptchaStrategy;
import org.kugua.utils.ImageUtils;
import org.kugua.utils.RandomUtils;

import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.List;

/**
 * 滑块验证码
 *
 * <p>
 *     优点: <br/>
 *     1. 方案实现简单,只需要进行简单的图层合并就行<br/>
 *     2. 效果比较理想<br/>
 *     缺点：<br/>
 *     1. 需要准备滑块和凹槽图片
 *
 * </p>
 *
 * @author 苦瓜
 * @create 2024-09-24
 * @since 1.0.0
 */
@Getter
@Setter
@Slf4j
public class SliderCaptchaStrategy2 extends AbstractSliderCaptchaStrategy {

    private ImageSelector<SliderImage> sliderSelector = new SliderImageSelector();

    /**
     * 缩放阈值
     */
    private double threshold = 0.4;

    /**
     * 缩放因子（缩放比例）
     */
    private double scaleFactor = 0.6;

    @Override
    public Captcha doFillContext(CaptchaContext context) {
        log.debug("SliderCaptchaStrategy2 doFillContext started.");
        Captcha slideCaptcha = new Captcha();
        // 背景图
        BufferedImage bgBufferedImage = selectImageIfNeedScale(context);
        Graphics2D graphics = context.getGraphics();
        SliderImage sliderImage = scaleIfNeed(sliderSelector.select(), context);
        // 生成滑块
        BufferedImage sliderBufferImage = generateSlideBlock(bgBufferedImage, sliderImage, slideCaptcha, context);
        // 绘制背景图
        graphics.drawImage(bgBufferedImage, 0, 0, context.getWidth(), context.getHeight(), null);
        String slider = toBase64(sliderBufferImage, getOutImageType());
        slideCaptcha.setSlider(slider);
        return slideCaptcha;
    }

    /**
     * 缩放处理
     *
     * @param originalSliderImage 原始图片
     * @param context 上下文
     * @return SliderImage
     */
    private SliderImage scaleIfNeed(SliderImage originalSliderImage, CaptchaContext context) {
        BufferedImage slider = originalSliderImage.getSlider();
        int w = slider.getWidth();
        int h = slider.getHeight();
        // 达到阈值之后，按照缩放因子进行缩放
        boolean isScaled = ((double) w / context.getWidth()) > threshold || ((double) h / context.getHeight()) > threshold;
        if (isScaled) {
            BufferedImage sliderImage = ImageUtils.scaleImage(slider, scaleFactor);
            BufferedImage grooveImage = ImageUtils.scaleImage(originalSliderImage.getGroove(), scaleFactor);
            originalSliderImage.setGroove(grooveImage);
            originalSliderImage.setSlider(sliderImage);
        }
        return originalSliderImage;
    }

    @Override
    public String getType() {
        return CaptchaEnum.SLIDE.getType();
    }

    /**
     * 生成滑块
     *
     * @param bufferedImage 背景图
     * @param sliderImage 滑块图片
     * @param slideCaptcha 验证码内容
     * @param context 上下文对象
     * @return BufferedImage
     */
    protected BufferedImage generateSlideBlock(BufferedImage bufferedImage, SliderImage sliderImage,
                                               Captcha slideCaptcha, CaptchaContext context) {
        log.debug("generate slider block.");
        // 1. 背景图上随机生成滑块位置
        BufferedImage grooveBufferedImage = sliderImage.getGroove();
        int grooveW = grooveBufferedImage.getWidth();
        int grooveH = grooveBufferedImage.getHeight();
        int maxX = bufferedImage.getWidth() - grooveW * 2;
        int maxY = bufferedImage.getHeight() - grooveH;
        int blockX = RandomUtils.random(grooveW, maxX);
        int blockY = RandomUtils.random(maxY);
        log.debug("generate slider coordinate,x:{}, y:{}", blockX, blockY);

        // 2.创建滑块
        BufferedImage slideBlockImage = new BufferedImage(grooveW, context.getHeight(),
                BufferedImage.TYPE_INT_RGB);
        Graphics2D slideGr = slideBlockImage.createGraphics();
        // 设置透明度
        BufferedImage compatibleImage = slideGr.getDeviceConfiguration()
                .createCompatibleImage(grooveW, context.getHeight(), Transparency.TRANSLUCENT);

        // 添加背景图层(即背景图中的凹槽部分到透明图层中)
        BufferedImage slideBlockBgImage = ImageUtils.cropImage(bufferedImage, grooveBufferedImage, blockX, blockY);
        Graphics2D g = compatibleImage.createGraphics();
        BufferedImage sliderBufferedImage = sliderImage.getSlider();
        g.drawImage(slideBlockBgImage, 0, blockY, slideBlockBgImage.getWidth(), slideBlockBgImage.getHeight(), null);
        // 添加滑块图片图层
        g.drawImage(sliderBufferedImage, 0, blockY, slideBlockBgImage.getWidth(), slideBlockBgImage.getHeight(), null);
        g.dispose();
        // 背景图上指定位置设置凹槽
        bufferedImage.createGraphics().drawImage(grooveBufferedImage, blockX, blockY, grooveW, grooveH, null);
        // 设置参数
        slideCaptcha.setAnswer(List.of(blockX + ""));
        return compatibleImage;
    }


}
